package cn.com.twoke.easyproject.modules.system.service.impl;

import cn.com.twoke.easyproject.common.utils.*;
import cn.com.twoke.easyproject.config.event.AsyncEventListener;
import cn.com.twoke.easyproject.modules.auth.event.UserLoginEvent;
import cn.com.twoke.easyproject.modules.auth.event.UserLogoutEvent;
import cn.com.twoke.easyproject.modules.auth.spi.AuthService;
import cn.com.twoke.easyproject.modules.auth.spi.pojo.LoginUserInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.com.twoke.easyproject.modules.system.domain.SysUser;
import cn.com.twoke.easyproject.modules.system.mapper.SysUserMapper;
import cn.com.twoke.easyproject.modules.system.service.SysUserService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Optional;

/**
 * (SysUser)表服务实现类
 *
 * @author TwoKe
 * @since 2025-06-07 03:42:35
 */
@Service("sysUserService")
@Slf4j
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService, AuthService {

    private final RedisUtil redisUtil;

    @Override
    public Serializable loginByUserNameAndPassword(String username, String password) {
        // 校验用户名
        SysUser sysUser = Optional.ofNullable(this.baseMapper.findByUsername(username))
                .orElseThrow(() -> ExceptionUtils.createBusiness("用户名或密码错误"));
        // 校验密码
        if (!sysUser.getPassword().equals(password)) {
          ExceptionUtils.throwBusinessException("用户名或密码错误");
        }
        return sysUser.getId();
    }

    @AsyncEventListener(UserLoginEvent.class)
    public void onUserLoginEvent(UserLoginEvent event) {
        long loginUserId = event.getLoginUserId();
        LocalDateTime now = LocalDateTime.now();
        log.info("用户登录：{} - {} - {} - {}", loginUserId, event.getIpAddress(), event.getLoginUserId(), now);
        this.update(new SysUser(), Wrappers.<SysUser>lambdaUpdate()
                        .set(SysUser::getLatestLoginTime, now)
                        .set(SysUser::getIpAddress, event.getIpAddress())
                        .set(SysUser::getIpRegion, event.getIpRegion())
                .eq(SysUser::getId, loginUserId)
        );
    }

    /**
     * 用户登录后设置用户的缓存信息
     * @param event
     */
    @EventListener(UserLoginEvent.class)
    public void onUserLoginCacheUserInfo(UserLoginEvent event) {
        SysUser sysUser = this.getOptById(event.getLoginUserId()).orElseThrow(() -> ExceptionUtils.createBusiness("用户名或密码错误"));
        redisUtil.set(String.format("token:login:user_info:%s", sysUser.getId()), sysUser);
    }

    @EventListener(UserLogoutEvent.class)
    public void onUserLogoutClearCacheUserInfo(UserLogoutEvent event) {
        long loginUserId = event.getLoginUserId();
        redisUtil.del(String.format("token:login:user_info:%s", loginUserId));
    }

    @AsyncEventListener(UserLogoutEvent.class)
    public void onUserLogoutEvent(UserLogoutEvent event) {
        long loginUserId = event.getLoginUserId();
        LocalDateTime now = LocalDateTime.now();
        log.info("用户登出：{} - {} - {} - {}", loginUserId, now);
        this.update(new SysUser(), Wrappers.<SysUser>lambdaUpdate()
                .set(SysUser::getLatestLogoutTime, now)
                .eq(SysUser::getId, loginUserId)
        );
    }



    @Override
    public LoginUserInfo getLoginUserInfoByUid(Serializable id) {
        SysUser userInfo = this.getOptById(id).orElseThrow(() -> ExceptionUtils.createBusiness("用户信息获取失败"));

        return new LoginUserInfo() {
            @Override
            public String getUid() {
                return IdUtils.encode(userInfo.getId());
            }

            @Override
            public String getUsername() {
                return userInfo.getUsername();
            }

            @Override
            public String getNickname() {
                return userInfo.getNickname();
            }

            @Override
            public String getAvatar() {
                return userInfo.getAvatar();
            }

            @Override
            public String getLatestIpAddress() {
                return userInfo.getIpAddress();
            }

            @Override
            public String getLatestIpRegion() {
                return userInfo.getIpRegion();
            }

            @Override
            public LocalDateTime getLatestLoginTime() {
                return userInfo.getLatestLoginTime();
            }

            @Override
            public LocalDateTime getLatestLogoutTime() {
                return userInfo.getLatestLogoutTime();
            }
        };
    }


}

